/*
 * lcd_init.cpp
 *
 *  Created on: 27.11.2011
 *      Author: Roma Jam
 */

#include "lcd_init.h"
#include "lcd_font.h"

void lcd_t::Init(){
    RCC_APB2PeriphClockCmd(LCD_CLK, ENABLE);    // Enable clock to PORTC
    // Setup pins' mode
    GPIO_InitTypeDef  GPIO_InitStr;
    GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz; // }
    GPIO_InitStr.GPIO_Mode = GPIO_Mode_Out_PP;  // } Common setting
    GPIO_InitStr.GPIO_Pin  = LCD_SCLK;
    GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStr);
    GPIO_InitStr.GPIO_Pin  = LCD_XCS;
    GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStr);
    GPIO_InitStr.GPIO_Pin  = LCD_XRES;
    GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStr);
    GPIO_InitStr.GPIO_Pin  = LCD_SDA;
    GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStr);
    GPIO_InitStr.GPIO_Pin =  LCD_BCKLT;      //Initialize Backlight of LCD
    GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStr);
//    LCD_BCKLT_ON();
    LCD_SCLK_LO();
    LCD_XCS_HI();
    // Reset display
    LCD_XRES_LO();
//    Delay.Loop(125000);  // about 5ms @ 24MHz
    LCD_XRES_HI();
    // Initial commands
#ifdef STEER
    LCD.WriteCmd (0x2A); // write VOP register
    LCD.WriteCmd (0x90);
#endif /* STEER */

#ifdef STM32
    LCD.WriteCmd (0x21); // write VOP register
    LCD.WriteCmd (0x90);
#endif /* STM32 */

    LCD.WriteCmd (0xC0); // Mirroring Y-axis

    LCD.WriteCmd(0xA4); // Set normal display mode
    LCD.WriteCmd(0x2F); // Charge pump on
    LCD.WriteCmd(0x40); // Set start row address = 0
    LCD.WriteCmd(0xAF); // display ON
    LCD.Clear(); // clear LCD
}

void lcd_t::Reset() {
    LCD.WriteCmd (0xE2);
}

void lcd_t::PrintMenu(uint8_t Ax_var, uint8_t Ay_var, uint32_t AOn, uint32_t AOff) {

}

void lcd_t::WriteCmd(uint8_t AByte) {
    LCD_SCLK_LO();
        LCD_XCS_LO();   // Select chip
        // Send "Cmd" bit
        LCD_SDA_LO();
        LCD_SCLK_HI();
        LCD_SCLK_LO();
        // Send byte
        for(uint8_t i=0; i<8; i++) {
            if(AByte & 0x80) LCD_SDA_HI();
            else LCD_SDA_LO();
            LCD_SCLK_HI();
            LCD_SCLK_LO();
            AByte <<= 1;
        }
        LCD_XCS_HI();
}

void lcd_t::WriteData(uint8_t AByte) {
    LCD_SCLK_LO();
        LCD_XCS_LO();   // Select chip
        // Send "Data" bit
        LCD_SDA_HI();
        LCD_SCLK_HI();
        LCD_SCLK_LO();
        // Send byte
        for(uint8_t i=0; i<8; i++) {
            if(AByte & 0x80) LCD_SDA_HI();
            else LCD_SDA_LO();
            LCD_SCLK_HI();
            LCD_SCLK_LO();
            AByte <<= 1;
        }
        LCD_XCS_HI();
}

void lcd_t::Clear(void) {
    LCD.WriteCmd(0x40); // Y = 0
    LCD.WriteCmd(0xB0);
    LCD.WriteCmd(0x10); // X = 0
    LCD.WriteCmd(0x00);
    for(uint16_t i=0;i<864;i++) LCD.WriteData(0x00);
}

void lcd_t::Clear_zone(const uint8_t x, const uint8_t y, uint8_t size_of_zone){
    uint8_t i;
    for (i=x; i<=(x+size_of_zone); i++) {
        LCD.PrintString(i, y, " ", false);
    }
}

void lcd_t::DrawChar(uint8_t AChar, bool AInvert) {
    uint8_t b;
    for(uint8_t i=0; i<6; i++) {
        b = Font_6x8_Data[AChar][i];
        if(AInvert) b = ~b;
        LCD.WriteData(b);
    }
 }

// ============================ Inner use ======================================
void lcd_t::GotoXY(uint8_t x, uint8_t y) {
    LCD.WriteCmd(0xB0|(y&0x0F));         // Y axis initialisation: 0100 yyyy
    LCD.WriteCmd(0x00|(x&0x0F));         // X axis initialisation: 0000 xxxx ( x3 x2 x1 x0)
    LCD.WriteCmd(0x10|((x>>4)&0x07));    // X axis initialisation: 0010 0xxx  ( x6 x5 x4)
}
void lcd_t::GotoXYstr(uint8_t x, uint8_t y) {
    x = (x<<2)+(x<<1);                   // x=x*6
    LCD.WriteCmd(0xB0|(y&0x0F));         // Y axis initialisation: 0100 yyyy
    LCD.WriteCmd(0x00|(x&0x0F));         // X axis initialisation: 0000 xxxx ( x3 x2 x1 x0)
    LCD.WriteCmd(0x10|((x>>4)&0x07));    // X axis initialisation: 0010 0xxx  ( x6 x5 x4)
}


void lcd_t::Show_Point (const uint8_t x, const uint8_t y, const uint8_t w) {
    uint8_t i;
    LCD.GotoXYstr(x-1,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x11][i]);
    LCD.GotoXYstr(x+w,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x10][i]);
}

void lcd_t::Clear_Point (const uint8_t x, const uint8_t y) {
    uint8_t i;
    LCD.GotoXYstr(x-1,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x00][i]);
    LCD.GotoXYstr(x+4,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x00][i]);
}
void lcd_t::Show_Left_Point (const uint8_t x, const uint8_t y) {
    uint8_t i;
    LCD.GotoXYstr(x-1,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x11][i]);
    LCD.GotoXYstr(x+4,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x00][i]);
}
void lcd_t::Show_Right_Point (const uint8_t x, const uint8_t y) {
    uint8_t i;
    LCD.GotoXYstr(x-1,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x00][i]);
    LCD.GotoXYstr(x+4,y);
    for (i=0; i<=6; i++) LCD.WriteData(Font_6x8_Data[0x10][i]);
}

void lcd_t::print_alpha(const uint8_t x, const uint8_t y) {
    uint8_t i, pos;
    pos = x;
    for (i=0; i<=6; i++) {
        LCD.GotoXY(pos,y);
        LCD.WriteData(alpha[i]);
        pos++;
    }
}
void lcd_t::print_betta(const uint8_t x, const uint8_t y) {
    uint8_t i, pos;
    pos = x;
    for (i=0; i<=6; i++) {
        LCD.GotoXY(pos,y);
        LCD.WriteData(gamma[i]);
        pos++;
    }
}
void lcd_t::print_angle(const uint8_t x, const uint8_t y) {
    uint8_t i, pos;
    pos = x;
    for (i=0; i<=6; i++) {
        LCD.GotoXY(pos,y);
        LCD.WriteData(angle[i]);
        pos++;
    }
}
void lcd_t::print_minute(const uint8_t x, const uint8_t y) {
    uint8_t i, pos;
    pos = x;
    for (i=0; i<=6; i++) {
        LCD.GotoXY(pos,y);
        LCD.WriteData(minute[i]);
        pos++;
    }
}
void lcd_t::Print (const uint8_t x, const uint8_t y, uint8_t data, bool AInvert) {
    LCD.GotoXYstr(x, y);
    if(AInvert) data = ~data;
    LCD.WriteData(data);
}

void lcd_t::PrintString (const uint8_t x, const uint8_t y, const char *S, bool AInvert) {
    LCD.GotoXYstr(x, y);
    while (*S != '\0')
        LCD.DrawChar(*S++, AInvert);
}

//void lcd_t::DrawImage(const uint8_t x, const uint8_t y, uint8_t *Img, bool AInvert) {
//    uint8_t *I = Img;
//    uint8_t Width = *I++, Height = *I++;
//    uint8_t b;
//    for(uint8_t fy=y; fy<y+Height; fy++) {
//        LCD.GotoXY(x, fy);
//        for(uint8_t fx=x; fx<x+Width; fx++) {
//            b = *I++;
//            if(AInvert) b = ~b;
//            LCD.WriteData(b);
//        } // fx
//    } // fy
//
//}

void lcd_t::Clear_Uint (const uint8_t x, const uint8_t y){
    uint8_t i, step;
        step = x;
        for (i=0; i<4; i++) {
            LCD.PrintString(step, y, " ", false);
            step++;
        }
}

void lcd_t::PrintUint(const uint8_t x, const uint8_t y, uint16_t ANumber, bool AInvert) {
    uint8_t digit = '0';
    bool ShouldPrint = false;
    const uint16_t FArr[4] = {10000, 1000, 100, 10};
    LCD.GotoXYstr(x, y);
    // Iterate until ANumber > 10
    for(uint8_t i=0; i<4; i++) {
        while (ANumber >= FArr[i]) {
            digit++;
            ANumber -= FArr[i];
        }
        if((digit != '0') || ShouldPrint) {
                LCD.DrawChar(digit, AInvert);
                ShouldPrint = true;
        }
        digit = '0';;
    }
    // Print last digit
    LCD.DrawChar('0'+ANumber, AInvert);
}

void lcd_t::PrintUint0_360(const uint8_t x, const uint8_t y, uint16_t ANumber, bool AInvert) {
    uint8_t digit = '0';
    bool ShouldPrint = false;
    const uint16_t FArr[4] = {100, 10};
    LCD.GotoXYstr(x, y);
    // Iterate until ANumber > 10
    for(uint8_t i=0; i<2; i++) {
        while (ANumber >= FArr[i]) {
            digit++;
            ANumber -= FArr[i];
        }
        LCD.DrawChar(digit, AInvert);
        if((digit != '0') && ShouldPrint) {
                LCD.DrawChar(digit, AInvert);
                ShouldPrint = true;
        }
        digit = '0';
    }
    // Print last digit
    LCD.DrawChar('0'+ANumber, AInvert);
}

void lcd_t::PrintUint0_60(const uint8_t x, const uint8_t y, uint16_t ANumber, bool AInvert) {
    uint8_t digit = '0';
    bool ShouldPrint = false;
    const uint16_t FArr[4] = {10, 1};
    LCD.GotoXYstr(x, y);
    // Iterate until ANumber > 10
    for(uint8_t i=0; i<1; i++) {
        while (ANumber >= FArr[i]) {
            digit++;
            ANumber -= FArr[i];
        }
        LCD.DrawChar(digit, AInvert);
        if((digit != '0') && ShouldPrint) {
                LCD.DrawChar(digit, AInvert);
                ShouldPrint = true;
        }
        digit = '0';
    }
    // Print last digit
    LCD.DrawChar('0'+ANumber, AInvert);
}

void lcd_t::PrintInt(const uint8_t x, const uint8_t y, int16_t ANumber, bool AInvert) {
    LCD.GotoXYstr(x, y);
    if(ANumber < 0) {
        LCD.DrawChar('-', AInvert);
        LCD.PrintUint(x+1, y, -ANumber, AInvert);
    }
    else LCD.PrintUint(x, y, -ANumber, AInvert);
}
// Print uint ANumber, 0<=ANumber<=99
void lcd_t::PrintUint0_99(const uint8_t x, const uint8_t y, uint8_t ANumber, bool AInvert) {
    uint8_t digit = '0';
    LCD.GotoXYstr(x, y);
    while(
            ANumber >= 10) {
        digit++;
        ANumber -= 10;
    }
    LCD.DrawChar(digit, AInvert);
    LCD.DrawChar('0'+ANumber, AInvert);
}
